﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using System.IO.IsolatedStorage;
using System.IO;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using GameStateManagement;
using Microsoft.Phone.Shell;
using System.Xml.Serialization;
using System.Net.Sockets;
using System.Net;

namespace PiratesOfBermuda
{
    public class ClientGameProcessor : MultiPlayerGameProcessor
    {
        bool isConnected = false;
        bool isInitting = false;
        float reconnectTime = 0.5f;
        float currentReconnectTime = 0.0f;
        bool isEnding = false;

        public ClientGameProcessor(Game game, SpriteBatch spriteBatch)
            : base(game, spriteBatch)
        {
            //Khoi gan luot choi
            //Host di truoc, Client di sau
            isPlayerTurn = false;            
        }

        void TryToConnectHost(float elapsed)
        {
            currentReconnectTime += elapsed;

            if (currentReconnectTime >= reconnectTime)
            {
                Channel.Send("ClientConnecting");
                currentReconnectTime = 0.0f;
            }
        }

        #region PROCESS PACKETS
        protected override void checkConnectedState(UdpPacketReceivedEventArgs e)
        {
            string[] mess = e.Message.Split(',');
            if (!isConnected && e.Message.Contains("HostAccepted"))
            {
                isInitting = true;                
                opponentIndentifier = mess[0];
            }
        }

        protected override void handleMessagesFromOpponent(string[] messages)
        {
            if (messages[1] == "InitDone" && isInitting)
            {
                isInitting = false;
                isConnected = true;
            }
            else
            {
                switch (messages[1])
                {
                    case "Init":
                        Init(messages);
                        break;
                    case "Move":
                    case "MoveAndWhirl":
                        ObjectsCustomMove(messages);
                        break;
                    
                    case "ChangeTurn":
                        isPlayerTurn = true;
                        player.IsActive = true;
                        isEnemyShipMoveSoundPlayed = false;
                        break;

                    case "Update":
                        MyUpdate(messages);
                        break;

                    case "GameStateChanged":
                        ChangeState(messages);
                        break;

                    //Nhan thong diep tan cong tu Host
                    case "Fire":
                        handleFireEventFromOpponent(messages);
                        break;
                }
            }
        }

        void Init(string[] messages)
        {
            int _x, _y;
            _x = Int32.Parse(messages[3]);
            _y = Int32.Parse(messages[4]);

            switch (messages[2])
            {
                case "Host":
                    //GenerateOpponentPlayer(_x, _y, "Host");
                    GeneratePlayer(ref opponentPlayer, _x, _y, "Host");
                    break;
                case "Client":
                    GeneratePlayer(ref player, _x, _y, "Client");
                    break;
                case "Whirl":
                    whirls.Add(GenerateWhirl(_x, _y));
                    break;
                case "Island":
                    islands.Add(GenerateIsland(_x,_y));
                    break;
                case "Enemy":
                    enemies.Add(GenerateEnemy(_x, _y));
                    break;
            }
        }

        #endregion


        #region PACKETS PROCESS METHODS
        protected void MyUpdate(string[] messages)
        {        
            switch (messages[2])
            {
                case "RemoveEnemiesLastPosition":
                    foreach (BasicEnemy ene in enemies)
                    {
                        string lastKey = ene.LastPosition.X + "_" + ene.LastPosition.Y;
                        gameObjects.Remove(lastKey);
                    }
                    break;
                
                case "MarkPlayerDestroyed":
                    gameObjects[(messages[3] + "_" + messages[4])].Destroyed = true;
                    break;

                case "ReplaceWithRubble":
                    ReplaceWithRubble(new Point(Int32.Parse(messages[3]), Int32.Parse(messages[4])));
                    break;
                case "AddExplodeAnimation":
                    Animation explodeAnimation = new Animation(explodeTexture, new Point(20, 28), new Point(15, 1), new Point(int.Parse(messages[3]), int.Parse(messages[4])));
                    explodeAnimations.Add(explodeAnimation);
                    explodeAnimation.PlayFromFrameIndex(0);
                    break;

                case "RemoveDestroyedEnemy":
                    int index = int.Parse(messages[3]);
                    enemies.RemoveAt(index);
                    break;

                case "UpdateEnemyPosition":
                    foreach(BasicEnemy enemy in enemies)
                    {
                        string key = enemy.X + "_" + enemy.Y;
                        if(!gameObjects.ContainsKey(key))
                            gameObjects.Add(enemy.X + "_" + enemy.Y, enemy);
                    }
                    break;

                case "HostRespawn":
                    GeneratePlayer(ref opponentPlayer,int.Parse(messages[3]), int.Parse(messages[4]), "Host");
                    opponentPlayer.LifeRemained = --opponentLifeRemained;
                    break;
                case "ClientRespawn":
                    GeneratePlayer(ref player, int.Parse(messages[3]), int.Parse(messages[4]), "Client");
                    player.LifeRemained = --playerLifeRemained;
                    break;

                case "ClientPlayerEnded":
                    if (player.CurrentShipState != ShipState.Standby)
                        isEnding = true;
                    else
                        player.CurrentShipState = ShipState.Ended;
                    break;
                case "HostPlayerEnded":
                    opponentPlayer.CurrentShipState = ShipState.Ended;
                    break;
            }
        }

        private void ChangeState(string[] messages)
        {
            switch (messages[2])
            {
                case "PlayerLose":
                    gameState = GameState.PlayerLose;
                    break;

                case "ClientWin":
                    gameState = GameState.PlayerWin;
                    break;
                case "HostWin":
                    gameState = GameState.PlayerLose;
                    break;
                case "AllDead":
                    gameState = GameState.AllDead;
                    break;
            }
        }
        #endregion


        #region UPDATE
        public override void CheckGameObjectsState()
        {
            if (player.CurrentShipState == ShipState.Standby && isPlayerTurn && !player.IsActive)
            {
                isPlayerTurn = false;
                Channel.Send("ChangeTurn");
                if (isEnding)
                    player.CurrentShipState = ShipState.Ended;
            }
            else if (player.CurrentShipState == ShipState.Ended && isPlayerTurn)
            {
                isPlayerTurn = false;
                Channel.Send("ChangeTurn");
            }
        }

        public override void Update(GameTime gameTime)
        {
            if (!isInitting && !isConnected)
            {
                TryToConnectHost((float)gameTime.ElapsedGameTime.TotalSeconds);
            }
            else if (isConnected)
            {
                CheckGameObjectsState();
                base.Update(gameTime);
                UpdatePlayer(gameTime);
                UpdateOpponentPlayer(gameTime);

                foreach (Animation a in explodeAnimations)
                {
                    if (a.IsActive)
                        a.Update();
                }
            }
        }

        protected override void UpdateEnemies(GameTime gameTime)
        {
            //update tung enemy nhu binh thuong
            foreach (BasicEnemy enemy in enemies)
            {
                enemy.Update(gameTime);
            }
        }

        protected override void removeSpecifiedShip(string key)
        {
            if (gameObjects[key].GetType() == typeof(BasicEnemy))
            {
                base.removeSpecifiedShip(key);
            }
            else if (gameObjects[key].GetType() == typeof(Player))
            {
                gameObjects[key].Destroyed = true;
            }
        }

        protected override bool handlePlayersDestroyedEvent(ref Player tempPlayer)
        {
            return true;
        }

        #endregion

        #region DRAW

        public override void Draw(GameTime gameTime, SpriteFont font)
        {
            spriteBatch.Begin();
            DrawBackground();
            CheckAndDrawGameObjects(gameTime);
            CheckAndDrawAnimations();

            // Kiem tra trang thai cua game
            if (isConnected && gameState != GameState.Playing)
            {
                switch (gameState)
                {
                    case GameState.PlayerWin:
                        spriteBatch.DrawString(font, "Player Win !", new Vector2(0, 0), Color.SandyBrown);
                        break;
                    case GameState.PlayerLose:
                        spriteBatch.DrawString(font, "Player Lose !", new Vector2(0, 0), Color.SandyBrown);
                        break;
                    case GameState.AllDead:
                        spriteBatch.DrawString(font, "All Dead !", new Vector2(0, 0), Color.SandyBrown);
                        break;
                }
            }
            spriteBatch.End();
        }

        protected override void CheckAndDrawGameObjects(GameTime gameTime)
        {
            if (isConnected)
            {
                base.CheckAndDrawGameObjects(gameTime);
            }
        }

        protected override void CheckAndDrawAnimations()
        {
            if (isConnected)
            {
                DrawExplodeAnimations();
            }
        }

        #endregion

        #region Player Helper Method
        public override void HandleInput(List<GestureSample> gestures)
        {
            if (isConnected && isPlayerTurn && player.IsActive && gameState == GameState.Playing)
            {
                HandleUserInput(gestures, "Client");
                sendMessages();
            }
        }
        #endregion
    }
}